package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.jws.Oneway;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    //如果数据存储需要mysql的话，则这里需要引入mapper，但是现在只需要使用redis
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    /**
     * 添加购物车
     * @param skuId
     * @param skuNum
     * @param userId
     */
    @Override
    public void addToCart(Long skuId, Long skuNum, String userId) {
        /*
            1.先判断当前购物车中是否有该商品
            true:有这个商品，数量相加  更新数据
            false:直接插入数据
         */
        //分析使用哪个数据类型，以及key   分析可得使用hash结构：hset key field value , key = user:userId:cart , fild = skuId , value = cartInfo
        //hget key field ----- 获取购物车中的单个购物项       hvals key-----查看购物车列表
        String cartKey = getCartkey(userId);

        //第二种判断
        //        Boolean flag = this.redisTemplate.boundHashOps(cartKey).hasKey(skuId.toString());
        //        CartInfo cartInfo = (CartInfo) this.redisTemplate.boundHashOps(cartKey).get(skuId.toString());
        //        if(flag){
        //            //有这个商品
        //        }else {
        //            //没有这个商品
        //        }

        //value是购物项
        CartInfo cartInfoExist = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        //第一种判断
        if(cartInfoExist!=null){
            //更新数据
            cartInfoExist.setSkuNum(cartInfoExist.getSkuNum()+skuNum.intValue());
            //查询一下实时价格
            cartInfoExist.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            //将这个对象放入缓存
            this.redisTemplate.opsForHash().put(cartKey, skuId.toString(), cartInfoExist);
            //细节：
            cartInfoExist.setIsChecked(1);
            cartInfoExist.setUpdateTime(new Date());
        }else{
            //插入数据
            CartInfo cartInfo = new CartInfo();
            //赋值操作
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum.intValue());
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            //放入缓存
            this.redisTemplate.opsForHash().put(cartKey, skuId.toString(), cartInfo);
        }
        //如果要有过期时间的话
        //setCartKeyExpire(cartKey);
    }

    /**
     * 这个方法就是获取购物车的key
     * @param userId
     * @return
     */
    private String getCartkey(String userId) {
        return RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
    }

    /**
     * 设置购物车的过期时间
     * @param cartKey
     */
    private void setCartKeyExpire(String cartKey) {
        this.redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    /**
     * 获取购物车列表
     * @param userId
     * @param userTempId
     * @return
     */
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        /*
            1.判断是否登录，根据判断结果查询不同的购物车
            2.查询的结构需要排序
            3.有可能需要合并
                在登陆的情况下
                    未登录-->登录合并
                    合并完成之后，需要删除未登录购物车数据！

                    case1:有userId，没有userTempId
                    case2:没有userId，有userTempId
                    case3:有userId，有userTempId
                           登录情况下合并购物车：
                                先判断未登录购物车集合有数据
                                    true：有数据----就合并
                                    false：没有数据----只需要登录购物车数据
         */
        //声明一个集合来存储未登录数据
        List<CartInfo> noLoginCartInfoList = null;
        //属于未登录       完成case2业务逻辑
        if(!StringUtils.isEmpty(userTempId)){
            //获取key
            String cartkey = this.getCartkey(userTempId);
            //获取登录的购物车集合数据
            noLoginCartInfoList = this.redisTemplate.opsForHash().values(cartkey);
        }
        if(StringUtils.isEmpty(userId)){
            if(!CollectionUtils.isEmpty(noLoginCartInfoList)){
                //这个是集合的排序
                noLoginCartInfoList.sort((o1,o2)->{
                    //按照更新时间
                    return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
                });
            }
            //返回未登录数据
            return noLoginCartInfoList;
        }

        //-------------------------case1  and  case3--------------------------------

        List<CartInfo> LoginCartInfoList = null;
        //获取key
        String cartkey = this.getCartkey(userId);

        //合并思路二：
        //  hset key field value;       hvals key获取全部      hset key filed获取单个
        BoundHashOperations<String,String,CartInfo> boundHashOperations = this.redisTemplate.boundHashOps(cartkey);
        //判断购物车中的feild
        //        boundHashOperations.hasKey(skuId.toString());
        if(!CollectionUtils.isEmpty(noLoginCartInfoList)){
            //循环遍历未登录购物车集合
            for (CartInfo cartInfo : noLoginCartInfoList) {//在未登录购物车中的skuId  与登录的skuId相等
                if (boundHashOperations.hasKey(cartInfo.getSkuId().toString())) {
                    //合并业务逻辑  skuNum + skuNum  更新时间
                    CartInfo loginCartInfo = boundHashOperations.get(cartInfo.getSkuId().toString());
                    loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + cartInfo.getSkuNum());
                    loginCartInfo.setUpdateTime(new Date());
                    //最新价格
                    loginCartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));

                    //选中状态合并
                    if (cartInfo.getIsChecked().intValue() == 1) {
                        loginCartInfo.setIsChecked(1);
                    }
                    //修改缓存的数据
                    boundHashOperations.put(cartInfo.getSkuId().toString(), loginCartInfo);
                } else {
                    //直接添加到缓存
                    cartInfo.setUserId(userId);
                    cartInfo.setCreateTime(new Date());
                    cartInfo.setUpdateTime(new Date());
                    boundHashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
                }
            }
            //删除未登录购物车数据
            this.redisTemplate.delete(this.getCartkey(userTempId));
        }

        //获取到合并之后的数据
        LoginCartInfoList = this.redisTemplate.boundHashOps(cartkey).values();
        if(CollectionUtils.isEmpty(LoginCartInfoList)){
            return new ArrayList<>();
        }
        //合并之后的排序
        LoginCartInfoList.sort((o1,o2)->{
            return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
        });

        //合并思路一：
        //获取登录的购物车集合数据
        //        LoginCartInfoList = this.redisTemplate.opsForHash().values(cartkey);
        //判断
        //        if(!CollectionUtils.isEmpty(noLoginCartInfoList)){
        //            //合并购物车  合并的条件：判断就是根据skuId是否相等。
        //            //还有一种情况：判断选中状态
        //            for (CartInfo noLoginCartInfo : noLoginCartInfoList) {
        //                for (CartInfo loginCartInfo : LoginCartInfoList) {
        //                    if(noLoginCartInfo.getSkuId().intValue()==loginCartInfo.getSkuId().intValue()){
        //                        //合并业务逻辑
        //
        //                    }else {
        //                        //直接添加
        //                    }
        //                }
        //            }
        //        }

        return LoginCartInfoList;
    }

    /**
     * 选中状态
     * @param userId
     * @param skuId
     * @param isChecked
     */
    @Override
    public void checkCart(String userId, Long skuId, Long isChecked) {
        //操作redis   hget key filed value  ------>  hset key filed value
        String cartkey = this.getCartkey(userId);
        //获取缓存中的数据
        CartInfo cartInfo = (CartInfo) this.redisTemplate.opsForHash().get(cartkey, skuId.toString());
        //判断
        if(cartInfo!=null){
            cartInfo.setIsChecked(isChecked.intValue());
            //再次放入缓存
            this.redisTemplate.opsForHash().put(cartInfo, skuId.toString(), cartInfo);
        }

    }

    /**
     * 删除购物车数据
     * @param skuId
     * @param userId
     */
    @Override
    public void deleteCart(Long skuId, String userId) {
        //获取购物车的key
        String cartkey = this.getCartkey(userId);
        //第一种直接删除  hdel key field
        //Long delete = this.redisTemplate.boundHashOps(cartkey).delete(skuId.toString());

        //第二种
        Boolean res = this.redisTemplate.boundHashOps(cartkey).hasKey(skuId.toString());
        if (res){
            this.redisTemplate.boundHashOps(cartkey).delete(skuId.toString());
        }
    }

    /**
     * 根据用户Id 来获取到购物车列表
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        String cartkey = this.getCartkey(userId);
        //获取到购物车集合数据
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartkey);
        //遍历找到isChecked = 1的数据
        //        List<CartInfo> cartInfos  = new ArrayList<>();
        //        for (CartInfo cartInfo : cartInfoList) {
        //            if(cartInfo.getIsChecked().intValue()==1){
        //                //给谁的？---》订单：给钱     再次确认一下最低价格
        //                cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
        //                cartInfos.add(cartInfo);
        //            }
        //        }

        //拉姆达表达式写法
        List<CartInfo> cartInfos = cartInfoList.stream().filter(cartInfo -> {
            //再次确认一下最低价格
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            return cartInfo.getIsChecked().intValue() == 1;
        }).collect(Collectors.toList());
        //返回数据
        return cartInfos;
    }

    /**
     * 删除购物车数据
     * @param userId
     */
    @Override
    public void delcart(String userId) {
        String cartkey = this.getCartkey(userId);
        //获取购物车数据
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartkey);
        //循环遍历
        for (CartInfo cartInfo : cartInfoList) {
            if(cartInfo.getIsChecked().intValue()==1){
                this.redisTemplate.opsForHash().delete(cartInfo, cartInfo.getSkuId().toString());
            }
        }
    }
}
